#include <vector>
#include <queue>
#include <string>
#include <pthread.h>
#include <mutex>
#include "Log.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"

using namespace ThreadModule;

const static int g_defaultThreadNum = 3;


template<typename T>
class ThreadPool
{
private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

    void ThreadWakeupAll()
    {
        pthread_cond_broadcast(&_cond);
    }

    void ThreadSleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void HandlerTask(std::string name)
    {
        LOG(INFO, "%s is running...", name.c_str());
        while(true) // 一直处理任务，直到队列中没有任务，退出
        {
            // 1. 访问任务队列，保证队列安全
            LockQueue();
            // 2. 判断队列中是否有数据

            // 2.1 如果队列为空，并且线程池是工作状态，则该线程等待
            while(_task_queue.empty() && _isRunning == true) 
            {
                _waitNum++;
                ThreadSleep(); // 在条件变量上等待

                // 等待结束，继续判断，防止伪唤醒
                _waitNum--;
            }

            // 2.2 如果队列为空，并且线程池退出，则退出循环
            if(_task_queue.empty() && _isRunning == false)
            {
                UnlockQueue();
                break;                
            }

            // 2.3 如果队列不为空，并且线程池退出，此时要先将队列中的任务完成，才能退出循环
            // 2.4 如果队列不为空，并且线程池未退出，取出任务，完成
            T t = _task_queue.front();
            _task_queue.pop();
            UnlockQueue();

            LOG(DEBUG, "%s, get a task", name.c_str());

            // 3. 执行任务
            // 执行的任务函数，参数为空，返回值也为空 
            t(); // 重载(), 也可以实现一个方法Run, t.Run()
            // LOG(DEBUG, "%s has finished a task, result is %s", name.c_str(), t.ResultToString().c_str());
        }
    }


    void InitThreadPool()
    {
        for(int i = 0; i < _threadNum; i++)
        {
            std::string name = "thread-" + std::to_string(i + 1);
            _threads.emplace_back(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1), name);
            LOG(INFO, "init thread %s done", name.c_str());
        }
    }


    void Start()
    {
        _isRunning = true;
        for(auto& thread: _threads)
        {
            thread.Start();
        }
    }

    // 私有构造函数
    ThreadPool(int threadNum = g_defaultThreadNum) : _threadNum(threadNum), _waitNum(0), _isRunning(false)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        LOG(INFO, "ThreadPool Construct()");
    }
    // 禁用赋值重载和拷贝构造
    ThreadPool<T>& operator=(const ThreadPool<T>&) = delete;
    ThreadPool(const ThreadPool<T>&) = delete;

public:

    // 提供一个工厂方法获取对象(懒汉模式)
    static ThreadPool<T>* GetInstance(int threadNum = g_defaultThreadNum)
    {
        // 对于多线程获取线程池对象要保证线程安全：需要加锁
        // 同时，只有第一次创建对象时需要保证线程安全，其余不需要（如果获取锁，性能有所消耗）

        // 这里不需要保证线程安全
        if(nullptr == _instance)
        {
            // 第一次获取对象时，创建对象
            LockGruad lockguard(&_itlock);
            if(nullptr == _instance)
            {
                _instance = new ThreadPool<T>(threadNum);
                // 这里可以做一些额外的工作：初始化线程池、启动线程池
                _instance->InitThreadPool();
                _instance->Start();
                LOG(DEBUG, "创建线程池单例");
                return _instance;
            }
        }
        LOG(DEBUG, "获取线程池单例");
        return _instance;
    }

    bool Push(const T& t)
    {
        bool ret = false;
        LockQueue();
        if(_isRunning == true)
        {
            _task_queue.push(t);
            if(_waitNum > 0)
                ThreadWakeup();

            LOG(DEBUG, "Push task success");
            ret = true;
        }
        UnlockQueue();
        return ret;
    }

    void Stop()
    {
        LockQueue();
        _isRunning = false;
        ThreadWakeupAll();
        UnlockQueue();
    }

    void Wait()
    {
        for(auto& thread : _threads)
        {
            thread.Join();
            LOG(INFO, "%s is quit...", thread.name().c_str());
        }
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        LOG(INFO, "ThreadPool Destruct()");
    }
private:
    int _threadNum;
    std::vector<Thread> _threads;
    std::queue<T> _task_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    int _waitNum;
    bool _isRunning;

    // 设计单例模式
    static ThreadPool<T>* _instance;
    static pthread_mutex_t _itlock;
};

// 在类外初始化
template<typename T>
ThreadPool<T>* ThreadPool<T>::_instance = nullptr;

template<typename T>
pthread_mutex_t ThreadPool<T>::_itlock =  PTHREAD_MUTEX_INITIALIZER;